package easy.netty.net.core;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.AttributeKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.UUID;

/**
 * @author cengy
 */
public class IoHandler
        extends SimpleChannelInboundHandler {

    private static final Logger
            logger = LoggerFactory.getLogger(IoHandler.class);

    protected final AttributeKey<IoSession> Io_Session_Key =
            AttributeKey.valueOf("Io_Session_Key");

    protected Endpoint endpoint;

    public IoHandler(Endpoint endpoint) {
        this.endpoint = endpoint;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        IoSession newSession = endpoint.getClass().newInstance();
        newSession.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        ctx.channel().attr(Io_Session_Key).set(newSession);
        newSession.setChannel(ctx.channel());

        Entity entity = new Entity(newSession);
        newSession.setEntity(entity);

        endpoint.getIoMgr().add(entity);
        endpoint.channelActive(newSession);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {

        Channel channel = ctx.channel();
        IoSession session = channel.attr(Io_Session_Key).getAndSet(null);
        endpoint.getIoMgr().remove(session.getEntity());
        endpoint.channelInActive(session);

        if (endpoint.getIoService() != null
                && endpoint.getIoService() instanceof Connector) {

            IoConf conf = endpoint.getIoConf();
            if (null != conf && conf.isAutoConnect()) {
                endpoint.open();
            }
        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        Channel channel = ctx.channel();
        IoSession session = channel.attr(Io_Session_Key).get();
        endpoint.channelEvent(session, evt);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable t) throws Exception {
        Channel channel = ctx.channel();
        IoSession session = channel.attr(Io_Session_Key).getAndSet(null);
        endpoint.channelError(session, t);
        // need close this channel?
        // ctx.channel().close();
        endpoint.getIoMgr().remove(session.getEntity());
        endpoint.channelInActive(session);
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        Channel channel = ctx.channel();
        IoSession session = channel.attr(Io_Session_Key).get();
        endpoint.channelRead(session, msg);
    }

}
